/**
 * 
 * Wuyts Sam	
 * 2Ba Ingenieurwetenschappen 
 * Hoofdrichting Werktuigkunde
 * Nevenrichting Computerwetenschappen 
 * https://ogp-sam-michiel.googlecode.com/svn:Asteroids
 * 
 * Partner: Michiel Timmermans
 */
package asteroids;

import asteroids.model.programs.Program;
import be.kuleuven.cs.som.annotate.*;
import java.util.*;

public class World { // defensive class

	private final double xRange;
	private final double yRange;
	private static double upperX = Double.POSITIVE_INFINITY;
	private static double upperY = Double.POSITIVE_INFINITY;
	private List<Ship> ships;
	private List<Asteroid> asteroids;
	private List<Bullet> bullets;
	CollisionListener cL;
	private double nextProgExecute;

	/**
	 * 
	 * @param x
	 * @param y
	 * @throws IllegalArgumentException
	 *             | !isValidXRange(x) || !isValidYRange(y)
	 * @post | (new this).getWorldWidth() == x
	 * @post | (new this).getWorldHeight == y
	 * @invar | if(isValidXRange(x) && isValidYRange(y)) | this.getWorldWidth()
	 *        == x && this.getWorldHeight == y
	 * @invar | World.upperY == Double .POSITIVE_INFINITY == World.UpperX
	 */
	public World(double x, double y) throws IllegalArgumentException {
		if (isValidXRange(x)) {
			this.xRange = x;
		} else {
			throw new IllegalArgumentException();
		}

		if (isValidYRange(y)) {
			this.yRange = y;
		} else {
			throw new IllegalArgumentException();
		}
		ships = new ArrayList<Ship>();
		asteroids = new ArrayList<Asteroid>();
		bullets = new ArrayList<Bullet>();
		nextProgExecute = 0.2;

	}

	/**
	 * 
	 * @param collisionListener
	 * @throws NullPointerException
	 *             | collisionListener == null
	 * @post | (new this).getCollisionListener() == collisionListener
	 */
	@Basic
	public void setCollisionListener(CollisionListener collisionListener)
			throws NullPointerException {
		if (collisionListener == null)
			throw new NullPointerException();
		this.cL = collisionListener;
	}

	/**
	 * 
	 * @return | result == this.cL
	 */
	@Basic
	public CollisionListener getCollisionListener() {
		return this.cL;
	}

	/**
	 * 
	 * @return | result == this.xRange
	 */
	@Basic
	public double getWorldWidth() {
		return this.xRange;
	}

	/**
	 * 
	 * @return | result == this.yRange
	 */
	@Basic
	public double getWorldHeight() {
		return this.yRange;
	}

	/**
	 * 
	 * @param y
	 *            The y range to be checked.
	 * @return | result == ((y <= World.upperY) && (y >= 0))
	 */
	public boolean isValidYRange(double y) {
		return ((y <= World.upperY) && (y >= 0));
	}

	/**
	 * 
	 * @param x
	 *            The x range to be checked.
	 * @return | result == ((x <= World.upperX) && (x >= 0))
	 */
	public boolean isValidXRange(double x) {
		return ((x <= World.upperX) && (x >= 0));
	}

	/**
	 * 
	 * @param ship
	 *            Ship to be added.
	 * @post |(new this).getShips().contains(ship) == true, if
	 *       |!(this.getShips().contains(ship) || ship == null ||
	 *       |!this.canBeAdded(ship))
	 * @throws IllegalArgumentException
	 *             |(ships.contains(ship) || ship == null || |
	 *             !this.canBeAdded(ship))
	 */
	public void addShip(Ship ship) throws IllegalArgumentException {
		if (ships.contains(ship) || ship == null || !this.canBeAdded(ship)) {
			throw new IllegalArgumentException();
		}

		else {
			ship.setWorld(this);
			ships.add(ship);
		}
	}

	/**
	 * 
	 * @param asteroid
	 *            Asteroid to be added.
	 * @post | (new this).getAsteroids().contains(asteroid) == true, if
	 *       |!(this.getAsteroids().contains(asteroid) || asteroid == null ||
	 *       |!this.canBeAdded(asteroid))
	 * @throws IllegalArgumentException
	 *             |(asteroids.contains(asteroid) || asteroid == null || |
	 *             !this.canBeAdded(asteroid))
	 */
	public void addAsteroid(Asteroid asteroid) throws IllegalArgumentException {
		if (asteroids.contains(asteroid) || asteroid == null
				|| !isInsideWorldBounds(asteroid)) {
			throw new IllegalArgumentException();
		} else if (!this.canBeAdded(asteroid)) {
			// do nothing
		}

		else {
			asteroid.setWorld(this);
			asteroids.add(asteroid);
		}
	}

	/**
	 * 
	 * @param bullet
	 *            Bullet to be added.
	 * @post |(new this).getBullets().contains(bullet) == true, if
	 *       |!(this.getBullets().contains(bullet) || bullet == null ||
	 *       |!this.canBeAdded(bullet))
	 * @throws IllegalArgumentException
	 *             |(bullets.contains(bullet) || bullet == null ||
	 *             |!this.canBeAdded(bullet))
	 */
	public void addBullet(Bullet bullet) throws IllegalArgumentException {
		if (bullets.contains(bullet) || bullet == null
				|| !isInsideWorldBounds(bullet)) {
			throw new IllegalArgumentException();
		} else if (!this.canBeAdded(bullet)) {

		}

		else {
			bullet.setWorld(this);
			bullets.add(bullet);
		}
	}

	/**
	 * 
	 * @return |result == this.ships
	 */
	@Basic
	public List<Ship> getShips() {
		return this.ships;
	}

	/**
	 * 
	 * @return |result == this.asteroids
	 */
	@Basic
	public List<Asteroid> getAsteroids() {
		return this.asteroids;
	}

	/**
	 * 
	 * @return |result == this.bullets
	 */
	@Basic
	public List<Bullet> getBullets() {
		return this.bullets;
	}

	/**
	 * 
	 * @param thing
	 * @return | result== (isInsideWorldBounds(thing)) &&
	 *         |(!thing.overlap(ships.get(i))) &&
	 *         |(!thing.overlap(asteroids.get(i))) &&
	 *         |(!thing.overlap(asteroids.get(i))) , for all i.
	 * @throws NullPointerException
	 *             |thing == null
	 */
	public boolean canBeAdded(FlyingObject thing) throws NullPointerException {
		if (thing == null) {
			throw new NullPointerException();
		}
		if (thing instanceof Bullet) {
			Bullet bullet = (Bullet) thing;
			if (!bullet.getSource().hasFired(bullet))
				return false;
		}
		if (!this.isInsideWorldBounds(thing))
			return false;
		int i = 0;
		while (i < this.getShips().size()) {
			if (thing.overlap(this.getShips().get(i)))

				return false;
			i++;
		}
		i = 0;
		while (i < this.getAsteroids().size()) {
			if (thing.overlap(this.getAsteroids().get(i)))
				return false;
			i++;
		}
		i = 0;
		while (i < this.getBullets().size()) {
			if (thing.overlap(this.getBullets().get(i)))
				return false;
			i++;
		}
		return true;

	}

	/**
	 * 
	 * @param thing
	 *            The thing to be checked.
	 * @return | result == ( !((thing.getPosition().getX() - thing.getSize())
	 *         <0) |&& !((thing.getPosition().getY() - thing.getSize()) < 0) &&
	 *         |!((thing.getPosition().getX() + thing.getSize()) > this.xRange)
	 *         |&& !((thing.getPosition().getY() + thing.getSize()) >
	 *         this.yRange) )
	 * 
	 * @throws NullPointerException
	 *             | thing == null
	 */
	public boolean isInsideWorldBounds(FlyingObject thing)
			throws NullPointerException {

		if (thing == null) {
			throw new NullPointerException();
		}

		if ((thing.getPosition().getX() - thing.getSize()) < 0)
			return false;
		if ((thing.getPosition().getX() + thing.getSize()) > this
				.getWorldWidth())
			return false;
		if ((thing.getPosition().getY() + thing.getSize()) > this
				.getWorldHeight())
			return false;
		if ((thing.getPosition().getY() - thing.getSize()) < 0) {
			return false;
		}
		return true;
	}

	/**
	 * 
	 * @param thing
	 *            The entity to be destroyed.
	 * @post |!this.getShips().contains(thing) &&
	 *       !this.getAsteroids().contains(thing) &&
	 *       |!this.getBullets().contains(thing)
	 */
	public void destroyFlyingObject(FlyingObject thing) {
		if(thing == null) {}
		if ((thing instanceof Ship) && this.getShips().contains(thing))
			this.getShips().remove(thing);
		if ((thing instanceof Bullet) && this.getBullets().contains(thing)) {
			this.getBullets().remove(thing);
			((Bullet) thing).getSource().removeFiredBullet((Bullet) thing);
		}
		if ((thing instanceof Asteroid) && this.getAsteroids().contains(thing)) {
			this.getAsteroids().remove(thing);
			if (thing.getSize() > 30.0) {
				splitAsteroid((Asteroid) thing);
			}

		}
	}

	public void fireBullet(Ship ship) {
		double size = 3.0;
		double bulletPosX = ship.getPosition().getX()
				+ Math.cos(ship.getAngle().getAngle()) * ship.getSize();
		double bulletPosY = ship.getPosition().getY()
				+ Math.sin(ship.getAngle().getAngle()) * ship.getSize();
		Position bulletPos = new Position(bulletPosX, bulletPosY);
		Velocity bulletVel = new Velocity(250.0 * Math.cos(ship.getAngle()
				.getAngle()), 250.0 * Math.sin(ship.getAngle().getAngle()));
		Bullet bullet = new Bullet(bulletPos, bulletVel, size, ship);
		if (this.isInsideWorldBounds(bullet)) {
			this.addBullet(bullet);
		}

	}

	/**
	 * 
	 * @param asteroid
	 *            The asteroid to be split.
	 * @post | (new this).getAsteroids().size() = this.getAsteroids().size() +2
	 */
	private void splitAsteroid(Asteroid asteroid) throws NullPointerException {
		if (asteroid == null) {
			throw new NullPointerException();
		}
		double x = asteroid.getPosition().getX();
		double y = asteroid.getPosition().getY();
		Random random = new Random();
		double angle = random.nextDouble();
		double v = 1.5 * Math.sqrt(Math.pow(asteroid.getVelocity().getX(), 2)
				+ Math.pow(asteroid.getVelocity().getY(), 2));
		double radius = asteroid.getSize();

		addAsteroid(new Asteroid(new Position(x + radius / 2 * Math.cos(angle),
				y + radius / 2 * Math.sin(angle)), new Velocity(v
				* Math.cos(angle), v * Math.sin(angle)), radius / 2,
				random.nextDouble()));

		addAsteroid(new Asteroid(new Position(x + radius / 2
				* Math.cos(angle + Math.PI), y + radius / 2
				* Math.sin(angle + Math.PI)), new Velocity(v
				* Math.cos(angle + Math.PI), v * Math.sin(angle + Math.PI)),
				radius / 2, random.nextDouble()));
	}

	/**
	 * 
	 * @param deltaT
	 * @throws IllegalArgumentException
	 *             | deltaT < 0 || collisionListener == null
	 * @effect | ArrayList everything = new
	 *         ArrayList().addAll(this.getShips()).addAll
	 *         (this.getAsteroids()).addAll(this.getBullets()) |double
	 *         collisionTime1 = MIN({for all i,j with i !=j:
	 *         everything.get(i).getTimeToCollision(everything.get(j))}) |double
	 *         collisionTime2 = MIN({T: for all i :
	 *         !this.isInsideWorldBounds(everything.get(i).move(T)) : all t <T
	 *         this.isInsideWorldBounds(everything.get(i).move(t)) } |double
	 *         collisionTime = MIN(collisionTime1,collisionTime2)
	 *         |if(collisionTime > deltaT) | {for all
	 *         k:everything.get(k).move(deltaT)} |else {{for all
	 *         k:everything.get(k).move(collisionTime)}; |if(collisionTime =
	 *         collisionTime1) { |FlyingObject thing1 = everything.get(i):
	 *         collisionTime =
	 *         everything.get(i).getTimeToCollision(everything.get(j));
	 *         |FlyingObject thing2 = everything.get(i): collisionTime ==
	 *         everything.get(i).getTimeToCollision(everything.get(j)); with
	 *         thing1 != thing2 } |else {thing1 = {everything.get(k):
	 *         !this.isInsideWorldBounds(everything.get(k).move(collisionTime +
	 *         UTIL.EPSILON))} ; |thing2 = null;}
	 *         |resolveCollision(thing1,thing2); |evolve(deltaT-collisionTime);
	 *         }
	 */
	public void evolve(double deltaT) throws IllegalArgumentException {
		if (deltaT < 0) {
			throw new IllegalArgumentException();
		}
		double collisionTime = Double.POSITIVE_INFINITY;
		double secondCollisionTime = Double.POSITIVE_INFINITY;
		double testTime;
		FlyingObject thing1 = null;
		FlyingObject thing2 = null;
		int i = 0;
		int j = 1;
		ArrayList<FlyingObject> allObjects = new ArrayList<FlyingObject>();
		allObjects.addAll(this.getShips());
		allObjects.addAll(this.getAsteroids());
		allObjects.addAll(this.getBullets());
		while (i < allObjects.size()) {
			j = i + 1;
			while (j < allObjects.size()) {
				testTime = FlyingObject.getTimeToCollision(allObjects.get(i),
						allObjects.get(j));
				if (testTime < collisionTime) {
					secondCollisionTime = collisionTime;
					collisionTime = testTime;
					thing1 = allObjects.get(i);
					thing2 = allObjects.get(j);
				}
				j++;
			}
			i++;
		}
		i = 0;
		FlyingObject thing;
		while (i < allObjects.size()) {
			thing = allObjects.get(i);
			if ((thing.getVelocity().getX() > 0)
					&& Math.abs((this.getWorldWidth()
							- thing.getPosition().getX() - thing.getSize())
							/ thing.getVelocity().getX()) < collisionTime) {
				secondCollisionTime = collisionTime;
				collisionTime = Math.abs((this.getWorldWidth()
						- thing.getPosition().getX() - thing.getSize())
						/ thing.getVelocity().getX());
				thing1 = thing;
				thing2 = null;
			}
			if ((thing.getVelocity().getX() < 0)
					&& Math.abs((thing.getPosition().getX() - thing.getSize())
							/ thing.getVelocity().getX()) < collisionTime) {
				secondCollisionTime = collisionTime;
				collisionTime = Math.abs((thing.getPosition().getX() - thing
						.getSize()) / thing.getVelocity().getX());
				thing1 = thing;
				thing2 = null;
			}
			if ((thing.getVelocity().getY() > 0)
					&& Math.abs((this.getWorldHeight()
							- thing.getPosition().getY() - thing.getSize())
							/ thing.getVelocity().getY()) < collisionTime) {
				secondCollisionTime = collisionTime;
				collisionTime = Math.abs((this.getWorldHeight()
						- thing.getPosition().getY() - thing.getSize())
						/ thing.getVelocity().getY());
				thing1 = thing;
				thing2 = null;
			}
			if ((thing.getVelocity().getY() < 0)
					&& Math.abs((thing.getPosition().getY() - thing.getSize())
							/ thing.getVelocity().getY()) < collisionTime) {
				secondCollisionTime = collisionTime;
				collisionTime = Math.abs((thing.getPosition().getY() - thing
						.getSize()) / thing.getVelocity().getY());
				thing1 = thing;
				thing2 = null;
			}
			i++;
		}

		while (nextProgExecute < deltaT && nextProgExecute < collisionTime) {
			i = 0;
			while (i < allObjects.size()) {
				allObjects.get(i).move(nextProgExecute);
				i++;
				}
			deltaT = (deltaT - nextProgExecute);
			collisionTime = collisionTime-nextProgExecute;
			this.executePrograms();
			
		}

		if (collisionTime > deltaT) {
			i = 0;
			while (i < allObjects.size()) {
				allObjects.get(i).move(deltaT);
				i++;
			}
			nextProgExecute = nextProgExecute - deltaT;
		} else {
			double extraTime = Math.min(
					Math.min(secondCollisionTime - collisionTime, deltaT
							- collisionTime), nextProgExecute - collisionTime) / 2.0;
			i = 0;
			while (i < allObjects.size()) {
				allObjects.get(i).move(collisionTime + extraTime);
				i++;
			}

			resolveCollision(thing1, thing2);
			deltaT = deltaT - (collisionTime + extraTime);
			nextProgExecute = nextProgExecute - (collisionTime + extraTime);

			this.evolve(deltaT);

		}
	}

	private void executePrograms() {
		nextProgExecute = 0.2;
		int i = 0;
		while (i < this.getShips().size()) {
			this.getShips().get(i).executeProgram();
			i++;
		}
		
	}

	/**
	 * Resolve the collision of the two given entities, if one but not both is
	 * null, a collision of the non-null entity with the boundary is assumed.
	 * 
	 * @param thing1
	 *            The first colliding entity.
	 * @param thing2
	 *            the second colliding entity.
	 * @throws IllegalArgumentException
	 *             both entities are null |(thing1 == null && thing2 == null)
	 * 
	 * @effect |if(thing1 == null) this.boundaryBounce(thing1);
	 * @effect |if(thing2 == null) this.boundaryBounce(thing2);
	 * @effect |if(thing1 instanceof Ship && thing2 instanceof Ship)
	 *         |destroyFlyingObject(thing1); destroyFlyingObject(thing2);
	 * @effect |if (thing1 instanceof Bullet || thing2 instanceof Bullet) { |if
	 *         (!(thing1 instanceof Ship) && !(thing2 instanceof Ship))
	 *         {destroyFlyingObject(thing1); destroyFlyingObject(thing2); }
	 *         |else if (thing1 instanceof Bullet) {Ship source = ((Bullet)
	 *         thing1).getSource(); |if (source != thing2)
	 *         {destroyFlyingObject(thing1);destroyFlyingObject(thing2); } |else
	 *         {Ship source = ((Bullet) thing2).getSource(); |if (source !=
	 *         thing2) {destroyFlyingObject(thing1);destroyFlyingObject(thing2);
	 *         } }
	 * @effect |else if ((thing1 instanceof Asteroid && thing2 instanceof
	 *         Asteroid) || (thing1 instanceof Ship && thing2 instanceof Ship))
	 *         { bounce(thing1, thing2); }
	 * @effect |if ((thing1 instanceof Asteroid && thing2 instanceof Ship) ||
	 *         (thing1 instanceof Ship && thing2 instanceof Asteroid)) { |if
	 *         (thing1 instanceof Ship) {destroyFlyingObject(thing1);} | else
	 *         {destroyFlyingObject(thing2); } }
	 * 
	 */
	private void resolveCollision(FlyingObject thing1, FlyingObject thing2)
			throws IllegalArgumentException {

		if (thing1 == null && thing2 == null) {
			throw new IllegalArgumentException();
		}

		else if (thing1 == null || thing2 == null) {

			if (thing1 == null) {
				boundaryBounce(thing2);
			} else {
				boundaryBounce(thing1);
			}
		}

		else if (thing1 instanceof Bullet || thing2 instanceof Bullet) {

			if (!(thing1 instanceof Ship) && !(thing2 instanceof Ship)) {
				if (thing1 instanceof Bullet) {
					destroyFlyingObject(thing1);
					destroyFlyingObject(thing2);
				} else {
					destroyFlyingObject(thing2);
					destroyFlyingObject(thing1);
				}
				if(this.getCollisionListener() != null) {
				this.getCollisionListener().objectCollision(thing1, thing2,
						thing1.getPosition().getX(),
						thing1.getPosition().getY());
				}
			} else if (thing1 instanceof Bullet) {
				Ship source = ((Bullet) thing1).getSource();
				if (source != thing2) {
					destroyFlyingObject(thing1);
					destroyFlyingObject(thing2);
					if(this.getCollisionListener() != null) {
					this.getCollisionListener().objectCollision(thing1, thing2,
							thing1.getPosition().getX(),
							thing1.getPosition().getY());
				} }
			} else {
				Ship source = ((Bullet) thing2).getSource();
				if (source != thing1) {
					destroyFlyingObject(thing1);
					destroyFlyingObject(thing2);
					if(this.getCollisionListener() != null) {
					this.getCollisionListener().objectCollision(thing1, thing2,
							thing1.getPosition().getX(),
							thing1.getPosition().getY());
					}
				}
			}
		}

		else if ((thing1 instanceof Asteroid && thing2 instanceof Asteroid)
				|| (thing1 instanceof Ship && thing2 instanceof Ship)) {
			bounce(thing1, thing2);
		}

		else if ((thing1 instanceof Asteroid && thing2 instanceof Ship)
				|| (thing1 instanceof Ship && thing2 instanceof Asteroid)) {

			if (thing1 instanceof Ship) {
				destroyFlyingObject(thing1);
				Position collPos = thing1.getCollisionPosition(thing2);
				if(this.getCollisionListener() != null) {
					this.getCollisionListener().objectCollision(thing1, thing2,
						collPos.getX(), collPos.getY());
				}
			} else {
				destroyFlyingObject(thing2);
				Position collPos = thing2.getCollisionPosition(thing1);
				if(this.getCollisionListener() != null) {
					this.getCollisionListener().objectCollision(thing1, thing2,
						collPos.getX(), collPos.getY());
				}
			}
		}

	}

	/**
	 * 
	 * @param thing
	 *            The entity that bounces of the boundary.
	 * @effect |if((thing.getPosition().getX() - size < UTIL.EPSILON) ||
	 *         (thing.getPosition().getX() + size + UTIL.EPSILON >
	 *         this.getWorldWidth() ) thing.bounceX();
	 * @effect |if((thing.getPosition().getY() - size < UTIL.EPSILON) ||
	 *         (thing.getPosition().getY() + size + UTIL.EPSILON >
	 *         this.getWorldHeight() ) thing.bounceY();
	 * @effect | if(thing instanceof Bullet && thing.getBounces() == 1)
	 *         destroyFlyingObject(thing)
	 * @effect | if(thing instanceof Bullet && thing.getBounces() == 0)
	 *         thing.incrementBounces();
	 */
	private void boundaryBounce(FlyingObject thing) throws NullPointerException {
		if (thing == null)
			throw new NullPointerException();
		double size = thing.getSize();
		double x = thing.getPosition().getX();
		double y = thing.getPosition().getY();

		if ((x - size < Util.EPSILON)
				|| (x + size + Util.EPSILON > this.getWorldWidth())) {
			if (thing.getVelocity().getX() > 0) {
				if(this.getCollisionListener() != null) {
					this.getCollisionListener().boundaryCollision(thing,
						this.getWorldWidth(), thing.getPosition().getY()); }
			} else {
				if(this.getCollisionListener() != null) {
				this.getCollisionListener().boundaryCollision(thing, 0,
						thing.getPosition().getY());
				}
			}
			thing.BounceX();
		}
		if ((y - size < Util.EPSILON)
				|| (y + size + Util.EPSILON > this.getWorldHeight())) {
			if (thing.getVelocity().getY() > 0) {
				if(this.getCollisionListener() != null) {
				this.getCollisionListener().boundaryCollision(thing,
						thing.getPosition().getX(), this.getWorldHeight());
			} }else {
				if(this.getCollisionListener() != null) {
				this.getCollisionListener().boundaryCollision(thing,
						thing.getPosition().getX(), 0);
				}
			}
			thing.BounceY();
		}
		if (thing instanceof Bullet) {
			int bounces = ((Bullet) thing).getBounces();
			if (bounces > 1) {
				destroyFlyingObject(thing);
			} else {
				((Bullet) thing).incrementBounces();
			}
		}

	}

	/**
	 * 
	 * @param thing1
	 *            The first entity that is colliding.
	 * @param thing2
	 *            The second entity that is colliding.
	 * 
	 * @effect | double sqRadii = Math.pow(thing1.getSize() + thing2.getSize(),
	 *         2); |double xDiff = thing2.getPosition().getX() | -
	 *         thing1.getPosition().getX(); |double yDiff =
	 *         thing2.getPosition().getY() | - thing1.getPosition().getY();
	 *         |double vxDiff = thing2.getVelocity().getX() | -
	 *         thing1.getVelocity().getX(); |double vyDiff =
	 *         thing2.getVelocity().getY() | - thing1.getVelocity().getY();
	 *         |double m1 = thing1.getMass(); |double m2 = thing2.getMass();
	 *         |double j = 2.0 * m1 * m2 * (vxDiff * xDiff + vyDiff * yDiff) | /
	 *         (sqRadii * (m1 + m2)); |Velocity newV1 = new
	 *         Velocity(thing1.getVelocity().getX() + j * xDiff | / m1,
	 *         thing1.getVelocity().getY() + j * yDiff / m1);
	 *         |thing1.setVelocity(newV1); |Velocity newV2 = new
	 *         Velocity(thing2.getVelocity().getX() - j * xDiff | / m2,
	 *         thing2.getVelocity().getY() - j * yDiff / m2);
	 *         |thing2.setVelocity(newV2);
	 * 
	 * 
	 * 
	 * 
	 */
	private void bounce(FlyingObject thing1, FlyingObject thing2) {
		double sqRadii = Math.pow(thing1.getSize() + thing2.getSize(), 2);
		double xDiff = thing2.getPosition().getX()
				- thing1.getPosition().getX();
		double yDiff = thing2.getPosition().getY()
				- thing1.getPosition().getY();
		double vxDiff = thing2.getVelocity().getX()
				- thing1.getVelocity().getX();
		double vyDiff = thing2.getVelocity().getY()
				- thing1.getVelocity().getY();
		double m1 = thing1.getMass();
		double m2 = thing2.getMass();
		double j = 2.0 * m1 * m2 * (vxDiff * xDiff + vyDiff * yDiff)
				/ (sqRadii * (m1 + m2));
		Velocity newV1 = new Velocity(thing1.getVelocity().getX() + j * xDiff
				/ m1, thing1.getVelocity().getY() + j * yDiff / m1);
		thing1.setVelocity(newV1);
		Velocity newV2 = new Velocity(thing2.getVelocity().getX() - j * xDiff
				/ m2, thing2.getVelocity().getY() - j * yDiff / m2);
		thing2.setVelocity(newV2);

	}
}
